home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / NIH Image 1.55 / Source / File2.p < prev    next >
Encoding:
Text File  |  1994-04-25  |  69.5 KB  |  2,318 lines  |  [TEXT/PJMM]

  1. unit File2;
  2.  
  3. {Routines used by NIH Image for printing plus a few additional File Menu routines.}
  4.  
  5. interface
  6.  
  7.  
  8.     uses
  9.         QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, Lut;
  10.  
  11.  
  12.     procedure GetInfo;
  13.     procedure DoPageSetup;
  14.     procedure Print (ShowDialog: boolean);
  15.     procedure SetHalftone;
  16.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  17.     procedure TypeMismatch (fname: str255);
  18.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  19.     function GetTextFile (var name: str255; var RefNum: integer): boolean;
  20.     procedure InitTextInput (name: str255; RefNum: integer);
  21.     procedure GetLineFromText (var rLine: RealLine; var count: integer);
  22.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  23.     procedure PlotXYZ;
  24.     procedure SaveSettings;
  25.     procedure ExportAsText (fname: str255; RefNum: integer);
  26.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  27.     procedure Swap2Bytes (var i: integer);
  28.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  29.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean;
  30.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  31.     procedure GetTiffColorMap (f: integer);
  32.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  33.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  34.     function WriteExtraTiffIFDs (f: integer; ImageDataSize, cTabSize: LongInt): integer;
  35.     procedure SaveLUT (fname: str255; RefNum: integer);
  36.     procedure SaveColorTable (fname: str255; RefNum: integer);
  37.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  38.     procedure SaveOutline (fname: str255; RefNum: integer);
  39.     procedure OpenOutline (fname: str255; RefNum: integer);
  40.     function CheckIO (err: OSerr): integer;
  41.     function GetTIFFParameters (name: str255; RefNum: integer; var HasColorMap: boolean): boolean;
  42.     procedure GetXUnits (UnitsKind: UnitsType);
  43.     procedure GetUnitsKInd (var UnitsKind: UnitsType; var UnitsPerCM: double);
  44.  
  45.  
  46. implementation
  47.  
  48.     var
  49.         gstr: str255;
  50.  
  51.  
  52. {$PUSH}
  53. {$D-}
  54.  
  55.     procedure PrintErrCheck;
  56.         var
  57.             err: integer;
  58.             ticks: LongInt;
  59.     begin
  60.         err := PrError;
  61.         if err < 0 then
  62.             beep;
  63.     end;
  64.  
  65.  
  66.     procedure DoPageSetup;
  67.         var
  68.             result: boolean;
  69.     begin
  70.         PrOpen;
  71.         if PrintRecord = nil then begin
  72.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  73.                 PrintDefault(PrintRecord);
  74.             end;
  75.         if PrError = NoErr then begin
  76.                 result := PrValidate(PrintRecord);
  77.                 result := PrStlDialog(PrintRecord);
  78.             end;
  79.         PrClose;
  80.     end;
  81.  
  82.  
  83.     procedure PrintHalftone;
  84.         const
  85.             PostScriptBegin = 190;
  86.             PostScriptEnd = 191;
  87.             PostScriptHandle = 192;
  88.             TextIsPostScript = 194;
  89.         var
  90.             HexBufH: handle;
  91.             hloc, vloc, HexCount, iheight, iwidth, hstart, vstart: integer;
  92.             Height, Width, eof, angle, freq: str255;
  93.             aLine: LineType;
  94.             HexBuf: packed array[0..4200] of char;
  95.             err: OSErr;
  96.             table: LookupTable;
  97.  
  98.         procedure PutHEX (byt: integer);
  99.             var
  100.                 i, LowByte, HighByte, tmp: integer;
  101.                 h: char;
  102.         begin
  103.             if not info^.IdentityFunction then
  104.                 byt := table[byt];
  105.             byt := 255 - byt;
  106.             LowByte := byt mod 16;
  107.             byt := byt div 16;
  108.             HighByte := byt mod 16;
  109.             for i := 1 to 2 do begin
  110.                     if i = 1 then
  111.                         tmp := HighByte
  112.                     else
  113.                         tmp := LowByte;
  114.                     case tmp of
  115.                         0: 
  116.                             h := '0';
  117.                         1: 
  118.                             h := '1';
  119.                         2: 
  120.                             h := '2';
  121.                         3: 
  122.                             h := '3';
  123.                         4: 
  124.                             h := '4';
  125.                         5: 
  126.                             h := '5';
  127.                         6: 
  128.                             h := '6';
  129.                         7: 
  130.                             h := '7';
  131.                         8: 
  132.                             h := '8';
  133.                         9: 
  134.                             h := '9';
  135.                         10: 
  136.                             h := 'a';
  137.                         11: 
  138.                             h := 'b';
  139.                         12: 
  140.                             h := 'c';
  141.                         13: 
  142.                             h := 'd';
  143.                         14: 
  144.                             h := 'e';
  145.                         15: 
  146.                             h := 'f';
  147.                     end;
  148.                     hexbuf[HexCount] := h;
  149.                     HexCount := HexCount + 1;
  150.                     if HexCount mod 80 = 0 then begin
  151.                             HexBuf[HexCount] := cr;
  152.                             HexCount := HexCount + 1
  153.                         end;
  154.                 end;
  155.         end;
  156.  
  157.     begin
  158.         with info^ do begin
  159.                 if not IdentityFunction then
  160.                     GetLookupTable(table);
  161.                 MoveTo(-1, -1);
  162.                 LineTo(-1, -1); {Nothing prints without this dummy dot!}
  163.                 PicComment(PostScriptBegin, 0, nil); {See Tech Note #91}
  164.                 PicComment(TextIsPostScript, 0, nil);
  165.                 NumToString(HalftoneFrequency, freq);
  166.                 NumToString(HalftoneAngle, angle);
  167.                 if HalftoneDotFunction then
  168.                     DrawString(concat(freq, ' ', angle, ' {dup mul exch dup mul add 1 exch sub} setscreen'))
  169.                 else
  170.                     DrawString(concat(freq, ' ', angle, ' {pop} setscreen'));
  171.                 DrawString('0 0 translate');
  172.                 with RoiRect do begin
  173.                         iwidth := right - left;
  174.                         if iwidth > MaxLine then
  175.                             iwidth := MaxLine;
  176.                         iheight := bottom - top;
  177.                         hstart := left;
  178.                         vstart := top;
  179.                     end;
  180.                 NumToString(iwidth, width);
  181.                 NumToString(iheight, height);
  182.                 DrawString(concat(width, ' ', height, ' scale'));
  183.                 DrawString(concat('/PicStr ', width, ' string def'));
  184.                 DrawString(concat(width, ' ', height, ' 8 [', width, ' 0 0 ', height, ' 0 0]'));
  185.                 DrawString('{currentfile PicStr readhexstring pop} image');
  186.                 for vloc := vstart to vstart + iheight - 1 do begin
  187.                         GetLine(hstart, vloc, iwidth, aline);
  188.                         HexCount := 0;
  189.                         for hloc := 0 to iwidth - 1 do
  190.                             PutHex(aline[hloc]);
  191.                         HexBuf[HexCount] := cr;
  192.                         HexCount := HexCount + 1;
  193.                         err := PtrToHand(@HexBuf, HexBufH, HexCount);
  194.                         if err <> noErr then
  195.                             exit(PrintHalftone);
  196.                         PicComment(PostScriptHandle, HexCount, HexBufH);
  197.                         DisposHandle(HexBufH);
  198.                         Show2Values(vloc - vstart, iheight);
  199.                         if CommandPeriod then begin
  200.                                 beep;
  201.                                 eof := chr(4);
  202.                                 DrawString(eof);
  203.                                 exit(PrintHalftone)
  204.                             end;
  205.                     end;
  206.             end;
  207.     end;
  208.  
  209.  
  210.     procedure PrintTheImage (PageWidth, PageHeight: integer);
  211.         var
  212.             PrintRect: rect;
  213.             Width, Height: integer;
  214.  
  215.         procedure ScaleToFitPage;
  216.             var
  217.                 hscale, vscale, scale: real;
  218.         begin
  219.             hscale := PageWidth / width;
  220.             vscale := PageHeight / height;
  221.             if hscale <= vscale then
  222.                 scale := hscale
  223.             else
  224.                 scale := vscale;
  225.             width := trunc(scale * width);
  226.             height := trunc(scale * height);
  227.         end;
  228.  
  229.         procedure CenterOnPage;
  230.         begin
  231.             with PrintRect do begin
  232.                     left := 0;
  233.                     top := 0;
  234.                     if width < PageWidth then
  235.                         left := (PageWidth - width) div 2;
  236.                     if height < PageHeight then
  237.                         top := (Pageheight - height) div 2;
  238.                     right := left + width;
  239.                     bottom := top + height;
  240.                 end;
  241.         end;
  242.  
  243.     begin
  244.         if isLaserWriter and (not OptionKeyDown) and (not OptionKeyWasDown) and (not DriverHalftoning) then
  245.             PrintHalftone
  246.         else
  247.             with info^ do begin
  248.                     LoadLUT(cTable);
  249.                     hlock(handle(osPort^.portPixMap));
  250.                     with RoiRect do begin
  251.                             width := right - left;
  252.                             height := bottom - top;
  253.                         end;
  254.                     if (width > PageWidth) or (height > PageHeight) then
  255.                         ScaleToFitPage;
  256.                     CenterOnPage;
  257.                     if BitAnd(thePort^.portBits.rowBytes, $8000) = $8000 then begin
  258.                {Assume driver understands Color QD}
  259.                             hlock(handle(CGrafPort(ThePort^).PortPixMap));
  260.                             CopyBits(BitMapHandle(osPort^.portPixMap)^^, BitMapHandle(CGrafPort(ThePort^).PortPixMap)^^, RoiRect, PrintRect, SrcCopy, nil);
  261.                             hunlock(handle(CGrafPort(ThePort^).PortPixMap))
  262.                         end
  263.                     else
  264.                         CopyBits(BitMapHandle(osPort^.portPixMap)^^, thePort^.PortBits, RoiRect, PrintRect, SrcCopy, nil);
  265.                     hunlock(handle(osPort^.portPixMap));
  266.                 end;
  267.     end;
  268.  
  269.  
  270.     procedure PrintTextBuffer (PageHeight: integer; var PrintPort: TPPrPort);
  271.         const
  272.             LineInc = 13;
  273.         var
  274.             vloc, i, LineCount, CharCount, LinesPerPage, MaxCount: integer;
  275.             aLine: str255;
  276.     begin
  277.         ClipTextInBuffer := false;
  278.         LinesPerPage := PageHeight div LineInc;
  279.         vloc := LineInc;
  280.         LineCount := 0;
  281.         CharCount := 0;
  282.         TextFont(Monaco);
  283.         TextSize(9);
  284.         if WhatToPrint = PrintText then
  285.             MaxCount := 85
  286.         else
  287.             MaxCount := 255;
  288.         i := 1;
  289.         repeat
  290.             CharCount := 0;
  291.             while (TextBufP^[i] <> cr) and (CharCount < MaxCount) and (i <= TextBufSize) do begin
  292.                     CharCount := CharCount + 1;
  293.                     aLine[CharCount] := TextBufP^[i];
  294.                     i := i + 1;
  295.                 end;
  296.             if TextBufP^[i] = cr then
  297.                 i := i + 1
  298.             else if CharCount = MaxCount then begin
  299.                     while (aLine[CharCount] <> ' ') and (CharCount > (MaxCount - 15)) do begin
  300.                             CharCount := CharCount - 1;
  301.                             i := i - 1;
  302.                         end;
  303.                     if TextBufP^[i] = ' ' then
  304.                         i := i + 1;
  305.                 end;
  306.             aLine[0] := chr(CharCount);
  307.             MoveTo(0, vloc);
  308.             DrawString(aLine);
  309.             vLoc := vLoc + LineInc;
  310.             LineCount := LineCount + 1;
  311.             if LineCount >= LinesPerPage then begin
  312.                     LineCount := 0;
  313.                     if i < TextBufSize then begin
  314.                             PrClosePage(PrintPort);
  315.                             PrintErrCheck;
  316.                             PrOpenPage(PrintPort, nil);
  317.                             vloc := LineInc
  318.                         end;
  319.                 end;
  320.         until i > TextBufSize;
  321.     end;
  322.  
  323.  
  324.     procedure DoPrintText (PageHeight: integer; var PrintPort: TPPrPort);
  325.         var
  326.             ByteCount: LongInt;
  327.     begin
  328.         if TextInfo <> nil then
  329.             with TextInfo^.TextTE^^ do begin
  330.                     ByteCount := TELength;
  331.                     BlockMove(hText^, ptr(TextBufP), ByteCount);
  332.                     TextBufSize := ByteCount;
  333.                     PrintTextBuffer(PageHeight, PrintPort);
  334.                 end;
  335.     end;
  336.  
  337.  
  338.     procedure Print (ShowDialog: boolean);
  339.         var
  340.             err, i, LinesToPrint: Integer;
  341.             tPort: GrafPtr;
  342.             PrintPort: TPPrPort;
  343.             PrintStatusRec: TPrStatus;
  344.             prect: rect;
  345.             result: boolean;
  346.     begin
  347.         if WhatToPrint = PrintImage then
  348.             SelectAll(false);
  349.         if (WhatToPrint = PrintImage) or (WhatToPrint = PrintSelection) then begin
  350.                 if OpPending then
  351.                     KillRoi;
  352.                 with info^.RoiRect do
  353.                     LinesToPrint := bottom - top;
  354.                 if not DriverHalftoning then begin
  355.                         DrawLabels('Line:', 'Total:', '');
  356.                         Show2Values(0, LinesToPrint);
  357.                     end;
  358.             end;
  359.         GetPort(tPort);
  360.         PrOpen;
  361.         if PrintRecord = nil then begin
  362.                 PrintRecord := THPrint(NewHandle(SizeOF(TPrint)));
  363.                 PrintDefault(PrintRecord);
  364.             end;
  365.         if PrError = NoErr then begin
  366.                 InitCursor;
  367.                 result := PrValidate(PrintRecord);
  368.                 isLaserWriter := BSR(PrintRecord^^.prStl.wDev, 8) = 3;
  369.                 prect := PrintRecord^^.prInfo.rPage;
  370.                 if ShowDialog then
  371.                     result := PrJobDialog(PrintRecord)
  372.                 else
  373.                     result := true;
  374.                 if not DriverHalftoning then
  375.                     ShowMessage(CmdPeriodToStop);
  376.                 ShowWatch;
  377.                 if result then
  378.                     for i := 1 to PrintRecord^^.PrJob.icopies do begin
  379.                             PrintPort := PrOpenDoc(PrintRecord, nil, nil);
  380.                             PrintErrCheck;
  381.                             Printing := true;
  382.                             PrOpenPage(PrintPort, nil);
  383.                             if PrError = NoErr then
  384.                                 case WhatToPrint of
  385.                                     PrintImage, PrintSelection: 
  386.                                         PrintTheImage(prect.right, prect.bottom);
  387.                                     PrintMeasurements:  begin
  388.                                             CopyResultsToBuffer(1, mCount, true);
  389.                                             PrintTextBuffer(prect.Bottom, PrintPort);
  390.                                             UnsavedResults := false;
  391.                                         end;
  392.                                     PrintPlot: 
  393.                                         DrawPlot;
  394.                                     PrintHistogram: 
  395.                                         DrawHistogram;
  396.                                     PrintText: 
  397.                                         DoPrintText(prect.Bottom, PrintPort);
  398.                                 end;
  399.                             Printing := false;
  400.                             PrClosePage(PrintPort);
  401.                             PrintErrCheck;
  402.                             PrCloseDoc(PrintPort);
  403.                             PrintErrCheck;
  404.                             if PrintRecord^^.prJob.bJDocLoop = bSpoolLoop then
  405.                                 PrPicFile(PrintRecord, nil, nil, nil, PrintStatusRec);
  406.                         end;
  407.             end;
  408.         PrClose;
  409.         SetPort(tPort);
  410.         if WhatToPrint = PrintImage then
  411.             KillRoi;
  412.         ShowMessage(' ');
  413.     end;
  414.  
  415.  
  416.     procedure SetHalftone;
  417.         const
  418.             FrequencyID = 8;
  419.             AngleID = 10;
  420.             DotID = 4;
  421.             LineID = 5;
  422.         var
  423.             mylog: DialogPtr;
  424.             item, i, ignore, SaveFrequency, SaveAngle: integer;
  425.             SaveFunction: boolean;
  426.             str: str255;
  427.     begin
  428.         if DriverHalftoning then begin
  429.                 PutMessage('Custom halftoning is only available when Custom Grayscale Halftoning is checked in the Preferences dialog box.');
  430.                 exit(SetHalftone);
  431.             end;
  432.         SaveFrequency := HalftoneFrequency;
  433.         SaveAngle := HalftoneAngle;
  434.         SaveFunction := HalftoneDotFunction;
  435.         mylog := GetNewDialog(30, nil, pointer(-1));
  436.         SetDNum(MyLog, FrequencyID, HalftoneFrequency);
  437.         SelIText(MyLog, FrequencyID, 0, 32767);
  438.         SetDNum(MyLog, AngleID, HalftoneAngle);
  439.         OutlineButton(MyLog, ok, 16);
  440.         if HalftoneDotFunction then
  441.             SetDialogItem(mylog, DotID, 1)
  442.         else
  443.             SetDialogItem(mylog, LineID, 1);
  444.         repeat
  445.             ModalDialog(nil, item);
  446.             if item = FrequencyID then
  447.                 HalftoneFrequency := GetDNum(MyLog, FrequencyID);
  448.             if item = AngleID then begin
  449.                     HalftoneAngle := GetDNum(MyLog, AngleID);
  450.                     if (HalftoneAngle < 0) or (HalftoneAngle > 180) then begin
  451.                             beep;
  452.                             HalftoneAngle := SaveAngle;
  453.                         end;
  454.                 end;
  455.             if (item >= DotID) and (item <= LineID) then begin
  456.                     for i := DotID to LineID do
  457.                         SetDialogItem(mylog, i, 0);
  458.                     SetDialogItem(mylog, item, 1);
  459.                     HalftoneDotFunction := item = DotID;
  460.                 end;
  461.         until (item = ok) or (item = cancel);
  462.         DisposDialog(mylog);
  463.         if item = cancel then begin
  464.                 HalftoneFrequency := SaveFrequency;
  465.                 HalftoneAngle := SaveAngle;
  466.                 HalftoneDotFunction := SaveFunction;
  467.             end;
  468.     end;
  469.  
  470.  
  471. {$POP}
  472.  
  473.     procedure GetFileInfo (name: str255; vnum: integer; var DateCreated, LastModified: str255);
  474.         var
  475.             FileParmBlock: ParmBlkPtr;
  476.             theErr: OSErr;
  477.             DateVar, TimeVar: str255;
  478.             Secs: LongInt;
  479.     begin
  480.         DateCreated := '';
  481.         new(FIleParmBlock);
  482.         if FileParmBlock <> nil then
  483.             with FileParmBlock^ do begin
  484.                     ioCompletion := nil;
  485.                     ioNamePtr := @name;
  486.                     ioVRefNum := vnum;
  487.                     ioFVersNum := 0;
  488.                     ioFDirIndex := 0;
  489.                     theErr := PBGetFInfo(FileParmBlock, false);
  490.                     if theErr = NoErr then begin
  491.                             Secs := ioFlCrDat;
  492.                             IUDateString(Secs, abbrevDate, DateVar);
  493.                             IUTimeString(Secs, true, TimeVar);
  494.                             DateCreated := concat(DateVar, '  ', TimeVar);
  495.                             Secs := ioFlMDDat;
  496.                             IUDateString(Secs, abbrevDate, DateVar);
  497.                             IUTimeString(Secs, true, TimeVar);
  498.                             LastModified := concat(DateVar, '  ', TimeVar);
  499.                         end;
  500.                     Dispose(FileParmBlock);
  501.                 end;
  502.     end;
  503.  
  504.  
  505.     procedure GetVolumnInfo (vnum: integer; var VolumnName: str255; var FreeSpace: LongInt);
  506.         var
  507.             theErr: OSErr;
  508.             SPtr: StringPtr;
  509.             VolParmBlock: ParmBlkPtr;
  510.     begin
  511.         VolumnName := '';
  512.         new(SPtr);
  513.         new(VolParmBlock);
  514.         if (SPtr <> nil) and (VolParmBlock <> nil) then
  515.             with VolParmBlock^ do begin
  516.                     SPtr^ := '';
  517.                     ioVRefNum := vnum;
  518.                     ioNamePtr := SPtr;
  519.                     ioCompletion := nil;
  520.                     ioVolIndex := -1;
  521.                     theErr := PBGetVInfo(VolParmBlock, false);
  522.                     VolumnName := ioNamePtr^;
  523.                     FreeSpace := ioVAlBlkSiz * ioVFrBlk;
  524.                     dispose(SPtr);
  525.                     dispose(VolParmBlock);
  526.                 end;
  527.     end;
  528.  
  529.  
  530.     function RoomForFile (fname: str255; RefNum: integer; slines, sPixelsPerLine: integer; SavingSelection: boolean): boolean;
  531.         var
  532.             err: OSErr;
  533.             f: integer;
  534.             VolumnName: str255;
  535.             FreeSpace, ExistingFileSize, NeededSize: LongInt;
  536.     begin
  537.         with info^ do begin
  538.                 ExistingFileSize := 0;
  539.                 RoomForFile := true;
  540.                 err := fsopen(fname, RefNum, f);
  541.                 if err = 0 then begin
  542.                         err := GetEOF(f, ExistingFileSize);
  543.                         err := fsClose(f);
  544.                     end;
  545.                 if ExistingFileSize <> 0 then begin
  546.                         if SavingSelection then
  547.                             NeededSize := LongInt(slines) * sPixelsPerLine
  548.                         else
  549.                             NeededSize := ImageSize;
  550.                         if StackInfo <> nil then
  551.                             with StackInfo^ do
  552.                                 NeededSize := NeededSize * nSlices + nSlices * SizeOf(StackIFDType);
  553.                         GetVolumnInfo(RefNum, VolumnName, FreeSpace);
  554.                         if (NeededSize - ExistingFileSize + 8192) > FreeSpace then begin
  555.                                 PutMessage('There is not enough free space on this disk to save this image.');
  556.                                 RoomForFile := false;
  557.                             end;
  558.                     end;
  559.             end;
  560.     end;
  561.  
  562.  
  563.     procedure GetInfo;
  564.         var
  565.             name, str, DateCreated, LastModified, VolumnName, str2: str255;
  566.             hloc, vloc, InfoWidth, InfoHeight: integer;
  567.             SaveRoiShowing: boolean;
  568.             FreeSpace, DataSize: LongInt;
  569.             SaveForeIndex, SaveBackIndex: integer;
  570.             ImageInfo, InfoWindowInfo: InfoPtr;
  571.             x1, y1, x2, y2, ulength, clength: real;
  572.             SaveGDevice: GDHandle;
  573.  
  574.         procedure NewLine;
  575.         begin
  576.             vloc := vloc + 13;
  577.             MoveTo(hloc, vloc);
  578.         end;
  579.  
  580.         procedure NewParagraph;
  581.         begin
  582.             vloc := vloc + 18;
  583.             MoveTo(hloc, vloc);
  584.         end;
  585.  
  586.     begin
  587.         InfoWidth := 260;
  588.         InfoHeight := 260;
  589.         with info^ do begin
  590.                 if RoiShowing then
  591.                     InfoHeight := InfoHeight + 50;
  592.                 if RoiShowing and (RoiType = LineRoi) then
  593.                     InfoHeight := InfoHeight + 20;
  594.                 if vref <> 0 then
  595.                     InfoHeight := InfoHeight + 60;
  596.                 name := concat('Info About ', title);
  597.                 SaveRoiShowing := RoiShowing;
  598.             end;
  599.         SaveForeIndex := ForegroundIndex;
  600.         SaveBackIndex := BackgroundIndex;
  601.         SetForegroundColor(BlackIndex);
  602.         SetBackgroundColor(WhiteIndex);
  603.         ImageInfo := info;
  604.         if NewPicWindow(name, InfoWidth, InfoHeight) then
  605.             with ImageInfo^ do begin
  606.                     InfoWindowInfo := Info;
  607.                     SaveGDevice := GetGDevice;
  608.                     SetGDevice(osGDevice);
  609.                     SetPort(GrafPtr(info^.osPort));
  610.                     TextFont(ApplFont);
  611.                     TextSize(9);
  612.                     hloc := 15;
  613.                     vloc := 10;
  614.                     NewLine;
  615.                     DrawBString('Name: ');
  616.                     DrawString(title);
  617.                     NewParagraph;
  618.                     DrawBString('Width: ');
  619.                     DrawXDimension(PixelsPerLine, 0);
  620.                     NewLine;
  621.                     DrawBString('Height: ');
  622.                     DrawYDimension(nlines, 0);
  623.                     if StackInfo <> nil then begin
  624.                             NewLine;
  625.                             DrawBString('Depth: ');
  626.                             DrawLong(StackInfo^.nSlices);
  627.                         end;
  628.                     NewLine;
  629.                     DrawBString('Size: ');
  630.                     if StackInfo <> nil then
  631.                         DataSize := PixMapSize * StackInfo^.nSlices
  632.                     else
  633.                         DataSize := PixMapSize;
  634.                     DrawLong((DataSize + 511) div 1024);
  635.                     DrawString('K');
  636.                     NewParagraph;
  637.                     GetFileInfo(title, vref, DateCreated, LastModified); {DateCreated:='';}
  638.                     if DateCreated <> '' then begin
  639.                             DrawBString('Creation Date: ');
  640.                             DrawString(DateCreated);
  641.                             NewLine;
  642.                             DrawBString('Last Modified: ');
  643.                             DrawString(LastModified);
  644.                             NewLine;
  645.                         end;
  646.                     if iVersion > 0 then begin
  647.                             DrawBString('Version: ');
  648.                             DrawString('Created by NIH Image ');
  649.                             DrawReal(iVersion / 100.0, 1, 2);
  650.                             NewLine;
  651.                         end;
  652.                     if vref <> 0 then begin
  653.                             GetVolumnInfo(vref, VolumnName, FreeSpace);
  654.                             if VolumnName <> '' then begin
  655.                                     DrawBString('Volume: ');
  656.                                     DrawString(VolumnName);
  657.                                     DrawString(' (');
  658.                                     DrawLong(FreeSpace div 1024);
  659.                                     DrawString('K free)');
  660.                                     NewParagraph;
  661.                                 end;
  662.                         end;
  663.                     DrawBString('Type: ');
  664.                     if StackInfo <> nil then
  665.                         str := concat('Stack (', long2str(StackInfo^.nSlices), '  slices)')
  666.                     else begin
  667.                             case PictureType of
  668.                                 pdp11: 
  669.                                     str := 'PDP-11';
  670.                                 NewPicture: 
  671.                                     str := 'New';
  672.                                 normal: 
  673.                                     str := 'Normal';
  674.                                 PictFile: 
  675.                                     str := 'PICT';
  676.                                 TiffFile, InvertedTIFF: 
  677.                                     str := 'TIFF';
  678.                                 Leftover: 
  679.                                     str := 'Left Over';
  680.                                 imported:  begin
  681.                                         if DataType = EightBits then
  682.                                             str := 'Imported 8-bit image'
  683.                                         else
  684.                                             str := 'Imported 16-bit image';
  685.                                     end;
  686.                                 FrameGrabberType: 
  687.                                     str := 'Camera';
  688.                                 BlankField: 
  689.                                     str := 'Blank Field';
  690.                                 ScionType: 
  691.                                     str := 'Camera(Scion)';
  692.                                 otherwise
  693.                                     ;
  694.                             end;
  695.                             if BinaryPic then
  696.                                 str := concat(str, ' (Binary)');
  697.                         end;
  698.                     DrawString(str);
  699.                     if StackInfo <> nil then
  700.                         with StackInfo^ do
  701.                             if SliceSpacing <> 0.0 then begin
  702.                                     NewLine;
  703.                                     DrawBString('Slice Spacing: ');
  704.                                     RealToString(SliceSpacing, 1, 1, str);
  705.                                     DrawString(str);
  706.                                     DrawString(' pixels');
  707.                                 end;
  708.                     NewLine;
  709.                     DrawBString('Lookup Table: ');
  710.                     case LutMode of
  711.                         PseudoColor: 
  712.                             str := concat('Pseudocolor (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  713.                         GrayScale: 
  714.                             str := concat('Grayscale (', long2str(ncolors), ', ', long2str(ColorStart), '-', long2str(ColorEnd), ')');
  715.                         ColorLut: 
  716.                             str := 'Color';
  717.                         CustomGrayscale: 
  718.                             str := 'Custom Grayscale';
  719.                         otherwise
  720.                     end;
  721.                     DrawString(str);
  722.                     NewLine;
  723.                     DrawBString('Magnification: ');
  724.                     if ScaleToFitWindow then begin
  725.                             DrawReal(magnification, 1, 2);
  726.                             DrawString(' (Scale to Window Mode)')
  727.                         end
  728.                     else begin
  729.                             DrawReal(magnification, 1, 0);
  730.                             DrawString(':1')
  731.                         end;
  732.                     NewLine;
  733.                     DrawBString('Scale: ');
  734.                     if SpatiallyCalibrated then begin
  735.                             DrawReal(xSpatialScale, 1, 3);
  736.                             DrawString(' pixels per ');
  737.                             DrawString(xUnit);
  738.                             if PixelAspectRatio <> 1.0 then begin
  739.                                     NewLine;
  740.                                     DrawBString('Pixel Aspect Ratio: ');
  741.                                     DrawReal(PixelAspectRatio, 1, 4);
  742.                                 end;
  743.                         end
  744.                     else
  745.                         DrawString('None');
  746.                     if DensityCalibrated then begin
  747.                             NewLine;
  748.                             DrawBString('Unit of Measure: ');
  749.                             if UnitOfMEasure = '' then
  750.                                 DrawString('None')
  751.                             else
  752.                                 DrawString(UnitOfMeasure)
  753.                         end;
  754.                     NewParagraph;
  755.                     DrawBString('Free RAM: ');
  756.                     DrawLong(FreeMem div 1024);
  757.                     DrawString('K');
  758.                     NewLine;
  759.                     DrawBString('Largest Free Block: ');
  760.                     DrawLong(MaxBlock div 1024);
  761.                     DrawString('K');
  762.                     if FrameGrabber <> NoFrameGrabber then begin
  763.                             NewLine;
  764.                             DrawBString('Frame Grabber: ');
  765.                             case FrameGrabber of
  766.                                 QuickCapture:  begin
  767.                                         if fgWidth = 768 then
  768.                                             DrawString('50Hz')
  769.                                         else
  770.                                             DrawString('60Hz');
  771.                                         DrawString(' Data Translation QuickCapture');
  772.                                     end;
  773.                                 ScionLG3:  begin
  774.                                         if fgWidth = 768 then
  775.                                             DrawString('50Hz')
  776.                                         else
  777.                                             DrawString('60Hz');
  778.                                         DrawString(' SCION LG-3 (');
  779.                                         DrawLong(MaxLG3Frames div 2);
  780.                                         DrawString(' MB)');
  781.                                     end
  782.                             end;
  783.                         end;
  784.                     NewParagraph;
  785.                     if RoiType <> NoRoi then begin
  786.                             DrawBString('Selection Type: ');
  787.                             case RoiType of
  788.                                 PolygonRoi: 
  789.                                     DrawString('Polygon');
  790.                                 FreehandRoi: 
  791.                                     DrawString('Freehand');
  792.                                 RectRoi: 
  793.                                     DrawString('Rectangle');
  794.                                 OvalRoi: 
  795.                                     DrawString('Oval');
  796.                                 LineRoi: 
  797.                                     DrawString('Straight Line');
  798.                                 FreeLineRoi: 
  799.                                     DrawString('Freehand Line');
  800.                                 SegLineRoi: 
  801.                                     DrawString('Segmented Line');
  802.                             end;
  803.                             NewLine;
  804.                             case RoiType of
  805.                                 PolygonRoi, FreehandRoi, RectRoi, OvalRoi: 
  806.                                     with RoiRect do begin
  807.                                             DrawBString('    Left: ');
  808.                                             DrawXDimension(left, 0);
  809.                                             NewLine;
  810.                                             DrawBString('    Top: ');
  811.                                             if InvertYCoordinates then
  812.                                                 DrawYDimension(PicRect.bottom - top - 1, 0)
  813.                                             else
  814.                                                 DrawYDimension(top, 0);
  815.                                             NewLine;
  816.                                             DrawBString('    Width: ');
  817.                                             DrawXDimension(right - left, 0);
  818.                                             NewLine;
  819.                                             DrawBString('    Height: ');
  820.                                             DrawYDimension(bottom - top, 0);
  821.                                         end;
  822.                                 LineRoi:  begin
  823.                                         info := ImageInfo;
  824.                                         GetLengthOrPerimeter(ulength, clength);
  825.                                         GetLoi(x1, y1, x2, y2);
  826.                                         Info := InfoWindowInfo;
  827.                                         DrawBString('    Length: ');
  828.                                         if SpatiallyCalibrated then begin
  829.                                                 DrawReal(cLength, 1, 2);
  830.                                                 DrawString(xUnit);
  831.                                             end
  832.                                         else
  833.                                             DrawReal(uLength, 1, 2);
  834.                                         NewLine;
  835.                                         DrawBString('    Angle: ');
  836.                                         DrawReal(LAngle, 1, 2);
  837.                                         DrawString('°');
  838.                                         NewLine;
  839.                                         DrawBString('    X1: ');
  840.                                         DrawXDimension(x1, 2);
  841.                                         NewLine;
  842.                                         DrawBString('    Y1: ');
  843.                                         if InvertYCoordinates then
  844.                                             DrawYDimension(PicRect.bottom - y1 - 1, 2)
  845.                                         else
  846.                                             DrawYDimension(y1, 2);
  847.                                         NewLine;
  848.                                         DrawBString('    X2: ');
  849.                                         DrawXDimension(x2, 2);
  850.                                         NewLine;
  851.                                         DrawBString('    Y2: ');
  852.                                         if InvertYCoordinates then
  853.                                             DrawYDimension(PicRect.bottom - y2 - 1, 2)
  854.                                         else
  855.                                             DrawYDimension(y2, 2);
  856.                                     end;
  857.                                 FreeLineRoi, SegLineRoi:  begin
  858.                                         info := ImageInfo;
  859.                                         GetLengthOrPerimeter(ulength, clength);
  860.                                         Info := InfoWindowInfo;
  861.                                         DrawBString('    Length: ');
  862.                                         if SpatiallyCalibrated then begin
  863.                                                 DrawReal(cLength, 1, 2);
  864.                                                 DrawString(xUnit);
  865.                                             end
  866.                                         else
  867.                                             DrawReal(uLength, 1, 2);
  868.                                         NewLine;
  869.                                     end;
  870.                                 otherwise
  871.                             end; {case}
  872.                         end
  873.                     else
  874.                         DrawBString('No Selection');
  875.                     SetGDevice(SaveGDevice);
  876.                 end; {with ImageInfo^}
  877.         SetForegroundColor(SaveForeIndex);
  878.         SetBackgroundColor(SaveBackIndex);
  879.     end;
  880.  
  881.  
  882.     function NewPtrClear (blockSize: Size): Ptr;
  883.     {This function will return a pointer of size specified and will}
  884.     {clear the memory to zeros . This is done to create an empty bit}
  885.     {map containing nothing but white bits . }
  886.  
  887.     {MOVE . L  ( SP ) + , D0  ; get Size variable from stack}
  888.     {_NewPtr , clear           ; make pointer }
  889.     {MOVE.L  A0 , ( SP )       ; return pointer }
  890.     {MOVE.W D0, MemErr     ; set up MemErr }
  891.     inline
  892.         $201F, $A31E, $2E88, $31C0, $0220;
  893.  
  894.  
  895.     function CheckIO (err: OSerr): integer;
  896.         var
  897.             ErrStr, Message: str255;
  898.             ignore: integer;
  899.     begin
  900.         if err <> 0 then begin
  901.                 Message := '';
  902.                 case err of
  903.                     -34: 
  904.                         Message := 'Disk Full';
  905.                     -36: 
  906.                         Message := 'I/O Error';
  907.                     -49: 
  908.                         Message := 'File in Use';
  909.                     -61: 
  910.                         Message := 'Write Permission Error';
  911.                 end;
  912.                 NumToString(err, ErrStr);
  913.                 ParamText(Message, ErrStr, '', '');
  914.                 InitCursor;
  915.                 ignore := alert(IOErrorID, nil);
  916.                 macro := false; {If macro, abort it}
  917.             end;
  918.         CheckIO := err;
  919.     end;
  920.  
  921.  
  922.     function OpenMacPaint (fname: str255; vnum: integer): boolean;
  923.         const
  924.             MaxUnPackedSize = 51840;   {Max MacPaint size in bytes=720 lines * 72 bytes/line }
  925.         type
  926.             mpLine = array[1..18] of LongInt;
  927.             mpArrayT = array[1..720] of mpLine;
  928.             mpArrayP = ^mpArrayT;
  929.         var
  930.             i, f, ScanLine, LastLine, LastWord, LastColumn: integer;
  931.             err: osErr;
  932.             srcSize: LongInt;
  933.             srcPtr, dstPtr, src, dst: ptr;
  934.             theBitMap: BitMap;
  935.             mpArray: mpArrayP;
  936.             BlankLine, BlankColumn: boolean;
  937.             frect: rect;
  938.             SaveGDevice: GDHandle;
  939.  
  940.         procedure abort;
  941.         begin
  942.             beep;
  943.             if srcPtr <> nil then
  944.                 DisposPtr(srcPtr);
  945.             if dstPtr <> nil then
  946.                 DisposPtr(dstPtr);
  947.             exit(OpenMacPaint);
  948.         end;
  949.  
  950.     begin
  951.         OpenMacPaint := false;
  952.         err := fsOpen(fname, vnum, f);
  953.         if CheckIO(err) <> noErr then
  954.             exit(OpenMacPaint);
  955.         err := GetEOF(f, srcSize);
  956.         srcSize := srcSize - 512;
  957.         srcPtr := NewPtr(srcSize);
  958.         if srcPtr = nil then
  959.             abort;
  960.         err := SetFPos(f, fsFromStart, 512);
  961.         err := fsRead(f, srcSize, srcPtr);
  962.         if CheckIO(err) <> noErr then
  963.             exit(OpenMacPaint);
  964.         err := fsClose(f);
  965.         dstPtr := NewPtrClear(MaxUnPackedSize);
  966.         if dstPtr = nil then
  967.             abort;
  968.         src := srcPtr;
  969.         dst := dstPtr;
  970.         for scanLine := 1 to 720 do
  971.             UnPackBits(src, dst, 72); {bumps both ptrs}
  972.         DisposPtr(srcPtr);
  973.         mpArray := mpArrayP(dstPtr);
  974.         LastLine := 720;
  975.         BlankLine := true;
  976.         repeat
  977.             for i := 1 to 18 do
  978.                 blankLine := BlankLine and (mpArray^[LastLine, i] = 0);
  979.             if BlankLine then
  980.                 LastLine := LastLine - 1;
  981.         until (not BlankLine) or (LastLine = 1);
  982.         LastWord := 18;
  983.         BlankColumn := true;
  984.         repeat
  985.             for i := 1 to LastLine do
  986.                 blankColumn := BlankColumn and (mpArray^[i, LastWord] = 0);
  987.             if BlankColumn then
  988.                 LastWord := LastWord - 1;
  989.         until (not BlankColumn) or (LastWord = 1);
  990.         LastColumn := LastWord * 32;
  991.         LastColumn := LastColumn + 8;
  992.         if LastColumn > 576 then
  993.             LastColumn := 576;
  994.         LastLine := LastLine + 8;
  995.         if LastLine > 720 then
  996.             LastLine := 720;
  997.         SetRect(frect, 0, 0, LastColumn, LastLine);
  998.         with theBitMap do begin
  999.                 baseAddr := dstPtr;
  1000.                 rowBytes := 72;
  1001.                 bounds := frect;
  1002.             end;
  1003.         if not NewPicWindow(fname, LastColumn, LastLine) then
  1004.             abort;
  1005.         SaveGDevice := GetGDevice;
  1006.         SetGDevice(osGDevice);
  1007.         SetForegroundColor(BlackIndex);
  1008.         SetBackgroundColor(WhiteIndex);
  1009.         with info^ do begin
  1010.                 hlock(handle(osPort^.portPixMap));
  1011.                 CopyBits(theBitMap, BitMapHandle(osPort^.PortPixMap)^^, frect, frect, SrcCopy, nil);
  1012.                 hunlock(handle(osPort^.PortPixMap));
  1013.                 DisposPtr(dstPtr);
  1014.                 PictureType := imported;
  1015.                 BinaryPic := true;
  1016.                 SetGDevice(SaveGDevice);
  1017.                 if PixMapSize > UndoBufSize then
  1018.                     PutWarning;
  1019.             end;
  1020.         OpenMacPaint := true;
  1021.     end;
  1022.  
  1023.  
  1024.     procedure TypeMismatch (fname: str255);
  1025.     begin
  1026.         PutMessage(concat('The file "', fname, '" is a different type, and therefore cannot be replaced'));
  1027.     end;
  1028.  
  1029.  
  1030.     procedure SaveAsMacPaint (fname: str255; RefNum: integer);
  1031.         const
  1032.             MaxFileSize = 53072;   { maximum MacPaint file size. }
  1033.         var
  1034.             TheInfo: FInfo;
  1035.             dstPtr, srcPtr, mpBufPtr: Ptr;
  1036.             i, f, scanLine, err, width, height: integer;
  1037.             dstBuffer: array[1..128] of LongInt;
  1038.             size, dstSize: LongInt;
  1039.             theBitMap: BitMap;
  1040.             mprect, srect, drect: rect;
  1041.  
  1042.         procedure abort;
  1043.         begin
  1044.             beep;
  1045.             if mpBufPtr <> nil then
  1046.                 DisposPtr(mpBufPtr);
  1047.             if f <> -1 then
  1048.                 err := fsclose(f);
  1049.             exit(SaveAsMacPaint);
  1050.         end;
  1051.  
  1052.     begin
  1053.         f := -1;
  1054.         err := GetFInfo(fname, RefNum, TheInfo);
  1055.         case err of
  1056.             NoErr: 
  1057.                 with TheInfo do begin
  1058.                         if fdType <> 'PNTG' then begin
  1059.                                 TypeMismatch(fname);
  1060.                                 exit(SaveAsMacPaint)
  1061.                             end;
  1062.                     end;
  1063.             FNFerr:  begin
  1064.                     err := create(fname, RefNum, 'MPNT', 'PNTG');
  1065.                     if CheckIO(err) <> 0 then
  1066.                         exit(SaveAsMacPaint);
  1067.                 end;
  1068.             otherwise
  1069.                 if CheckIO(err) <> 0 then
  1070.                     exit(SaveAsMacPaint);
  1071.         end;
  1072.         mpBufPtr := NewPtrClear(MaxFileSize);
  1073.         if mpBufPtr = nil then
  1074.             abort;
  1075.         ShowWatch;
  1076.         SetRect(mprect, 0, 0, 576, 720);
  1077.         with theBitMap do begin
  1078.                 baseAddr := mpBufPtr;
  1079.                 rowBytes := 72;
  1080.                 bounds := mprect;
  1081.             end;
  1082.         with info^ do begin
  1083.                 if roiShowing then
  1084.                     srect := RoiRect
  1085.                 else
  1086.                     srect := PicRect;
  1087.                 with srect do begin
  1088.                         width := right - left;
  1089.                         height := bottom - top;
  1090.                         if width > 576 then
  1091.                             width := 576;
  1092.                         if height > 720 then
  1093.                             height := 720;
  1094.                         right := left + width;
  1095.                         bottom := top + height;
  1096.                     end;
  1097.                 SetRect(drect, 0, 0, width, height);
  1098.                 hlock(handle(osPort^.portPixMap));
  1099.                 CopyBits(BitMapHandle(osPort^.PortPixMap)^^, theBitMap, srect, drect, srcCopy, nil);
  1100.                 hunlock(handle(osPort^.PortPixMap));
  1101.             end;
  1102.         err := fsOpen(fname, RefNum, f);
  1103.         if CheckIO(err) <> noErr then
  1104.             abort;
  1105.         for I := 1 to 128 do
  1106.             dstBuffer[I] := 0;
  1107.         Size := 512;
  1108.         err := FSWrite(f, Size, @dstBuffer);
  1109.         if CheckIO(err) <> noErr then
  1110.             abort;
  1111.         srcPtr := theBitMap.baseAddr;
  1112.         for scanLine := 1 to 720 do begin
  1113.                 dstPtr := @dstBuffer; { reset the pointer to bottom }
  1114.                 PackBits(srcPtr, dstPtr, 72); { bumps both ptrs}
  1115.                 dstSize := ord(dstPtr) - ord(@dstBuffer);{calc packed size}
  1116.                 err := fsWrite(f, dstSize, @dstBuffer);
  1117.                 if CheckIO(err) <> noErr then
  1118.                     abort;
  1119.             end;
  1120.         err := fsclose(f);
  1121.         DisposPtr(mpBufPtr);
  1122.         info^.changes := false;
  1123.     end;
  1124.  
  1125.  
  1126.     function GetTextFile (var name: str255; var RefNum: integer): boolean;
  1127.         var
  1128.             where: Point;
  1129.             typeList: SFTypeList;
  1130.             reply: SFReply;
  1131.             err: OSErr;
  1132.             pBlock: WDPBRec;
  1133.     begin
  1134.         where.v := 120;
  1135.         where.h := 120;
  1136.         typeList[0] := 'TEXT';
  1137.         SFGetFile(Where, '', nil, 1, typeList, nil, reply);
  1138.         if reply.good then
  1139.             with reply do begin
  1140.                     name := fname;
  1141.                     RefNum := vRefNum;
  1142.                     GetTextFile := true;
  1143.                 end
  1144.         else
  1145.             GetTextFile := false;
  1146.     end;
  1147.  
  1148.  
  1149.     procedure GetBuffer;
  1150.         var
  1151.             err: OSErr;
  1152.             count, FilePos: LongInt;
  1153.     begin
  1154.         count := MaxTextBufSize;
  1155.         err := fsread(Textf, count, ptr(TextBufP));
  1156.         TextBufSize := count;
  1157.         err := GetFPos(Textf, FilePos);
  1158.         if FilePos = TextFileSize then begin
  1159.                 TextBufSize := TextBufSize + 1;
  1160.                 if TextBufSize > MaxTextBufSize then
  1161.                     TextBufSize := MaxTextBufSize;
  1162.                 TextBufP^[TextBufSize] := eof;
  1163.                 err := fsclose(Textf);
  1164.             end;
  1165.         TextIndex := 1;
  1166.     end;
  1167.  
  1168.  
  1169.     function GetByte: char;
  1170.     begin
  1171.         GetByte := TextBufP^[TextIndex];
  1172.         TextIndex := TextIndex + 1;
  1173.         if TextIndex > MaxTextBufSize then
  1174.             GetBuffer;
  1175.     end;
  1176.  
  1177.  
  1178.     function GetNumber: real;
  1179.         var
  1180.             c: char;
  1181.             str: str255;
  1182.     begin
  1183.         repeat
  1184.             c := GetByte;
  1185.             if c = tab then begin
  1186.                     GetNumber := 0.0; {Assume 0 zero for missing value.}
  1187.                     exit(GetNumber);
  1188.                 end;
  1189.             if (c = cr) or (c = eof) then begin
  1190.                     TextEol := true;
  1191.                     TextEof := c = eof;
  1192.                     GetNumber := NoValue;
  1193.                     exit(GetNumber);
  1194.                 end;
  1195.         until c in ['0'..'9', '-', '.'];
  1196.         Str := '';
  1197.         while c in ['0'..'9', '+', '-', '.', 'e', 'E'] do begin
  1198.                 Str := concat(str, c);
  1199.                 c := GetByte;
  1200.                 if (c = cr) or (c = eof) then begin
  1201.                         TextEol := true;
  1202.                         TextEof := c = eof;
  1203.                     end;
  1204.             end;
  1205.         GetNumber := StringToReal(str);
  1206.     end;
  1207.  
  1208.  
  1209.     procedure GetLineFromText (var rLine: RealLine; var count: integer);
  1210.         var
  1211.             n: real;
  1212.     begin
  1213.         count := 0;
  1214.         if TextEof then
  1215.             exit(GetLineFromText);
  1216.         repeat
  1217.             n := GetNumber;
  1218.             if n <> NoValue then begin
  1219.                     count := count + 1;
  1220.                     rLine[count] := n;
  1221.                 end;
  1222.         until TextEol or (count = MaxLine);
  1223.         TextEol := false;
  1224.     end;
  1225.  
  1226.  
  1227.     procedure InitTextInput (name: str255; RefNum: integer);
  1228.         var
  1229.             err: OSErr;
  1230.     begin
  1231.         err := FSOpen(name, RefNum, Textf);
  1232.         err := GetEof(Textf, TextFileSize);
  1233.         err := SetFPos(Textf, fsFromStart, 0);
  1234.         ShowWatch;
  1235.         if WhatsOnClip = TextOnClip then
  1236.             WhatsOnClip := NothingOnClip;
  1237.         GetBuffer;
  1238.         TextEol := false;
  1239.         TextEof := false;
  1240.     end;
  1241.  
  1242.  
  1243.     function ImportTextFile (name: str255; RefNum: integer): boolean;
  1244.         var
  1245.             nRows, nColumns, count, i, vloc, BlankPixel, nPixelsPerLine: integer;
  1246.             rLine: RealLine;
  1247.             pvalue: real;
  1248.             min, max, ScaleFactor, DefaultValue, tvalue: extended;
  1249.             err: OSErr;
  1250.             line, BlankLine: LineType;
  1251.             TheInfo: FInfo;
  1252.     begin
  1253.         ImportTextFile := false;
  1254.         err := GetFInfo(name, RefNum, TheInfo);
  1255.         if TheInfo.fdType <> 'TEXT' then begin
  1256.                 PutMessage('File is not of type ''TEXT''.');
  1257.                 exit(ImportTextFile);
  1258.             end;
  1259.         InitTextInput(name, RefNum);
  1260.         nRows := 0;
  1261.         nColumns := 0;
  1262.         max := -10e-10;
  1263.         min := 10e10;
  1264.         ShowMessage(concat('First pass used to find ', cr, 'width, height,min, and max.', cr, cr, CmdPeriodToStop));
  1265.         DrawLabels('Line:', '', '');
  1266.         while not TextEof do begin
  1267.                 GetLineFromText(rLine, count);
  1268.                 if not (TextEof and (count = 0)) then
  1269.                     nRows := nRows + 1;
  1270.                 if count > nColumns then
  1271.                     nColumns := count;
  1272.                 for i := 1 to count do begin
  1273.                         pvalue := rLine[i];
  1274.                         if pvalue > max then
  1275.                             max := pvalue;
  1276.                         if pvalue < min then
  1277.                             min := pvalue;
  1278.                     end;
  1279.                 if nRows mod 10 = 0 then begin
  1280.                         Show1Value(nRows, NoValue);
  1281.                         if CommandPeriod then begin
  1282.                                 beep;
  1283.                                 err := fsclose(Textf);
  1284.                                 Exit(ImportTextFile);
  1285.                             end;
  1286.                     end;
  1287.             end;
  1288.         ShowMessage(concat('rows= ', long2str(nRows), cr, 'columns= ', long2str(ncolumns), cr, 'min= ', long2str(round(min)), cr, 'max= ', long2str(round(max))));
  1289.         if nColumns > MaxLine then begin
  1290.                 PutMessage('More than 2048 pixels per line.');
  1291.                 Exit(ImportTextFile);
  1292.             end;
  1293.         nPixelsPerLine := nColumns;
  1294.         if NewPicWindow(name, nPixelsPerLine, nrows) then
  1295.             with info^ do begin
  1296.                     if (not ImportAutoScale) and (max > min) then begin
  1297.                             min := ImportMin;
  1298.                             max := ImportMax;
  1299.                         end;
  1300.                     ScaleFactor := 253.0 / (max - min);
  1301.                     InitTextInput(name, RefNum);
  1302.                     vloc := 0;
  1303.                     DefaultValue := 0.0;
  1304.                     if DefaultValue < min then
  1305.                         DefaultValue := min;
  1306.                     if DefaultValue > max then
  1307.                         DefaultValue := max;
  1308.                     BlankPixel := round((DefaultValue - min) * ScaleFactor + 1);
  1309.                     for i := 0 to nColumns - 1 do
  1310.                         BlankLine[i] := BlankPixel;
  1311.                     DrawLabels('Line:', 'Total:', '');
  1312.                     while not TextEof do begin
  1313.                             GetLineFromText(rLine, count);
  1314.                             if not (TextEof and (count = 0)) then begin
  1315.                                     line := BlankLine;
  1316.                                     if ImportAutoScale then     {Map values into the range 1-254}
  1317.                                         for i := 1 to count do
  1318.                                             line[i - 1] := round((rLine[i] - min) * ScaleFactor + 1)
  1319.                                     else
  1320.                                         for i := 1 to count do begin
  1321.                                                 tvalue := rLine[i];
  1322.                                                 if tvalue < min then
  1323.                                                     tvalue := min;
  1324.                                                 if tvalue > max then
  1325.                                                     tvalue := max;
  1326.                                                 line[i - 1] := round((tvalue - min) * ScaleFactor + 1);
  1327.                                             end;
  1328.                                     PutLine(0, vloc, PixelsPerLine, line);
  1329.                                     vloc := vloc + 1;
  1330.                                 end;
  1331.                             if vloc mod 10 = 0 then begin
  1332.                                     Show2Values(vloc, nRows);
  1333.                                     if CommandPeriod then begin
  1334.                                             beep;
  1335.                                             err := fsclose(Textf);
  1336.                                             Exit(ImportTextFile);
  1337.                                         end;
  1338.                                 end;
  1339.                         end;
  1340.                     fit := StraightLine;
  1341.                     nCoefficients := 2;
  1342.                     coefficient[2] := (max - min) / 253.0;
  1343.                     coefficient[1] := min - coefficient[2];
  1344.                     DensityCalibrated := true;
  1345.                     UpdateTitleBar;
  1346.                     if macro then
  1347.                         GenerateValues;
  1348.                     ZeroClip := false;
  1349.                     changes := true;
  1350.                     PictureType := imported;
  1351.                 end; {with}
  1352.         ImportTextFile := true;
  1353.     end;
  1354.  
  1355.  
  1356.     procedure PlotXYZ;
  1357. {Reads X-Y coordinate pairs and optional intensiy(Z) values from a}
  1358. {two or three column tab-delimited text file and plots them in the current window.}
  1359.         var
  1360.             fname, str: str255;
  1361.             RefNum, i, nColumns, nValues, index, wheight: integer;
  1362.             rLine: RealLine;
  1363.     begin
  1364.         RefNum := 0;
  1365.         if not GetTextFile(fname, RefNum) then
  1366.             exit(PlotXYZ);
  1367.         InitTextInput(fname, RefNum);
  1368.         GetLineFromText(rLine, nValues);
  1369.         nColumns := nValues;
  1370.         if not ((nColumns = 2) or (nColumns = 3)) then begin
  1371.                 PutMessage('File must have two or three columns.');
  1372.                 exit(PlotXYZ);
  1373.             end;
  1374.         wheight := info^.nLines;
  1375.         index := ForegroundIndex;
  1376.         repeat
  1377.             if nColumns = 3 then begin
  1378.                     index := round(rLine[3]);
  1379.                     if index > 255 then
  1380.                         index := 255;
  1381.                     if index < 0 then
  1382.                         index := 0;
  1383.                 end;
  1384.             PutPixel(round(rLine[1]), wheight - round(rLine[2] + 1), index);
  1385.             GetLineFromText(rLine, nValues);
  1386.         until nValues = 0;
  1387.         InitCursor;
  1388.     end;
  1389.  
  1390.  
  1391. {$IFC false}
  1392.  
  1393.     procedure SaveDefaultWorkingDir (var settings: SettingsType);
  1394.         var
  1395.             DefaultVRefNum, err: integer;
  1396.             DefaultDirID: LongInt;
  1397.             ProcID: LongInt;
  1398.     begin
  1399.         with settings do begin
  1400.                 if DefaultRefNum <> 0 then begin
  1401.                         err := GetWDInfo(DefaultRefNum, DefaultVRefNum, DefaultDirID, ProcID);
  1402.                         if err = NoErr then begin
  1403.                                 sDefaultVRefNum := DefaultVRefNum;
  1404.                                 sDefaultDirID := DefaultDirID;
  1405.                             end
  1406.                         else
  1407.                             beep;
  1408.                     end;
  1409.        {ShowMessage(concat('KernelsRefNum=', long2str(KernelsRefNum), cr, 'vRefNum=', long2str(sKernelsVRefNum), cr, 'DirID=', long2str(sKernelsDirID)));}
  1410.             end; {with}
  1411.     end;
  1412.  
  1413.  
  1414.     procedure SaveKernelsWorkingDir (var settings: SettingsType);
  1415.         var
  1416.             KernelsVRefNum, err: integer;
  1417.             KernelsDirID: LongInt;
  1418.             ProcID: LongInt;
  1419.     begin
  1420.         with settings do begin
  1421.                 if KernelsRefNum <> 0 then begin
  1422.                         err := GetWDInfo(KernelsRefNum, KernelsVRefNum, KernelsDirID, ProcID);
  1423.                         if err = NoErr then begin
  1424.                                 sKernelsVRefNum := KernelsVRefNum;
  1425.                                 sKernelsDirID := KernelsDirID;
  1426.                             end
  1427.                         else
  1428.                             beep;
  1429.                     end;
  1430.       {ShowMessage(concat('KernelsRefNum=', long2str(KernelsRefNum), cr, 'vRefNum=', long2str(sKernelsVRefNum), cr, 'DirID=', long2str(sKernelsDirID)));}
  1431.             end; {with}
  1432.     end;
  1433. {$ENDC}
  1434.  
  1435.  
  1436.     procedure SaveSettings;
  1437.         var
  1438.             TheInfo: FInfo;
  1439.             ByteCount: LongInt;
  1440.             f, i: integer;
  1441.             err: OSErr;
  1442.             settings: SettingsType;
  1443.     begin
  1444.         with settings, info^ do begin
  1445.                 sID := 'IMAG';
  1446.                 sVersion := version;
  1447.                 sForegroundIndex := ForegroundIndex;
  1448.                 sBackgroundIndex := BackgroundIndex;
  1449.                 sBrushHeight := BrushHeight;
  1450.                 sBrushWidth := BrushWidth;
  1451.                 sSprayCanDiameter := SprayCanDiameter;
  1452.                 sLUTMode := LUTMode;
  1453.                 sOldColorStart := 30;
  1454.                 sOldColorWidth := 10;
  1455.                 sCurrentFontID := CurrentFontID;
  1456.                 sCurrentStyle := CurrentStyle;
  1457.                 sCurrentSize := CurrentSize;
  1458.                 sTextJust := TextJust;
  1459.                 sTextBack := TextBack;
  1460.                 sNExtraColors := nExtraColors;
  1461.                 sExtraColors := ExtraColors;
  1462.                 sInvertVideo := InvertVideo;
  1463.                 sMeasurements := Measurements;
  1464.                 sInvertPlots := InvertPlots;
  1465.                 sAutoScalePlots := AutoScalePlots;
  1466.                 sLinePlot := LinePlot;
  1467.                 sDrawPlotLabels := DrawPlotLabels;
  1468.                 for i := 1 to 12 do
  1469.                     sUnused1[i] := 0;
  1470.                 sFixedSizePlot := FixedSizePlot;
  1471.                 sProfilePlotWidth := ProfilePlotWidth;
  1472.                 sProfilePlotHeight := ProfilePlotHeight;
  1473.                 sFramesToAverage := FramesToAverage;
  1474.                 sNewPicWidth := NewPicWidth;
  1475.                 sNewPicHeight := NewPicHeight;
  1476.                 sBufferSize := BufferSize;
  1477.                 sMaxScionWidth := MaxScionWidth;
  1478.                 sThresholdToForeground := ThresholdToForeground;
  1479.                 sNonThresholdToBackground := NonThresholdToBackground;
  1480.                 sVideoChannel := VideoChannel;
  1481.                 sWhatToImport := WhatToImport;
  1482.                 sImportCustomWidth := ImportCustomWidth;
  1483.                 sImportCustomHeight := ImportCustomHeight;
  1484.                 sImportCustomOffset := ImportCustomOffset;
  1485.                 sWandAutoMeasure := WandAutoMeasure;
  1486.                 sWandAdjustAreas := WandAdjustAreas;
  1487.                 sBinaryIterations := BinaryIterations;
  1488.                 sScaleArithmetic := ScaleArithmetic;
  1489.                 sInvertPixelValues := InvertPixelValues;
  1490.                 sInvertYCoordinates := InvertYCoordinates;
  1491.                 sFieldWidth := FieldWidth;
  1492.                 sPrecision := precision;
  1493.                 sMinParticleSize := MinParticleSize;
  1494.                 sMaxParticleSize := MaxParticleSize;
  1495.                 sIgnoreParticlesTouchingEdge := IgnoreParticlesTouchingEdge;
  1496.                 sLabelParticles := LabelParticles;
  1497.                 sOutlineParticles := OutlineParticles;
  1498.                 sIncludeHoles := IncludeHoles;
  1499.                 sOscillatingMovies := OscillatingMovies;
  1500.                 sDriverHalftoning := DriverHalftoning;
  1501.                 sMaxMeasurements := MaxMeasurements;
  1502.                 sImportCustomDepth := ImportCustomDepth;
  1503.                 sImportSwapBytes := ImportSwapBytes;
  1504.                 sImportCalibrate := ImportCalibrate;
  1505.                 sImportAutoscale := ImportAutoscale;
  1506.                 for i := 1 to 12 do
  1507.                     sUnused2[i] := 0;
  1508.                 sShowHeadings := ShowHeadings;
  1509.                 sDefaultVRefNum := 0;
  1510.                 sDefaultDirID := 0;
  1511.                 sKernelsVRefNum := 0;
  1512.                 sKernelsDirID := 0;
  1513.         {***}
  1514.                 sProfilePlotMin := ProfilePlotMin;
  1515.                 sProfilePlotMax := ProfilePlotMax;
  1516.                 sImportMin := ImportMin;
  1517.                 sImportMax := ImportMax;
  1518.                 sHighlightPixels := HighlightSaturatedPixels;
  1519.         {***}
  1520.                 sBallRadius := BallRadius;
  1521.                 sFasterBackgroundSubtraction := FasterBackgroundSubtraction;
  1522.                 sScaleConvolutions := ScaleConvolutions;
  1523.         {V1.42}
  1524.                 sBinaryCount := BinaryCount;
  1525.                 sColorTable := ColorTable;
  1526.                 sColorStart := ColorStart;
  1527.                 sColorEnd := ColorEnd;
  1528.                 sInvertedTable := InvertedColorTable;
  1529.         {V1.44}
  1530.                 sHalftoneFrequency := HalftoneFrequency;
  1531.                 sHalftoneAngle := HalftoneAngle;
  1532.                 sHalftoneDotFunction := HalftoneDotFunction;
  1533.                 sLG3DacLow := LG3DacLow;
  1534.                 sLG3DacHigh := LG3DacHigh;
  1535.                 sSyncMode := SyncMode;
  1536.                 sSwitchLUTOnSuspend := SwitchLUTOnSuspend;
  1537.                 sVideoRateAveraging := VideoRateAveraging;
  1538.                 sImportInvert := ImportInvert;
  1539.                 sTextCreator := TextCreator;
  1540.                 for i := 1 to 10 do
  1541.                     sUnused[i] := 0;
  1542.             end; {with}
  1543. {PBGetWDInfo seems to crash a lot, particularly under System 7. Does anyone know why?}
  1544. {SaveDefaultWorkingDir(settings);}
  1545. {SaveKernelsWorkingDir(settings);}
  1546.         err := GetFInfo(PrefsName, SystemRefNum, TheInfo);
  1547.         if err = FNFerr then begin
  1548.                 err := create(PrefsName, SystemRefNum, 'Imag', 'PREF');
  1549.                 if CheckIO(err) <> 0 then
  1550.                     exit(SaveSettings);
  1551.             end;
  1552.         err := fsopen(PrefsName, SystemRefNum, f);
  1553.         if CheckIO(err) <> 0 then
  1554.             exit(SaveSettings);
  1555.         err := SetFPos(f, FSFromStart, 0);
  1556.         ByteCount := SizeOf(settings);
  1557.         err := fswrite(f, ByteCount, @settings);
  1558.         if CheckIO(err) <> 0 then begin
  1559.                 err := fsclose(f);
  1560.                 exit(SaveSettings)
  1561.             end;
  1562.         err := SetEof(f, ByteCount);
  1563.         err := fsclose(f);
  1564.         err := FlushVol(nil, SystemRefNum);
  1565.     end;
  1566.  
  1567.  
  1568.     procedure ExportAsText (fname: str255; RefNum: integer);
  1569.         var
  1570.             err, f, width, hloc, vloc: integer;
  1571.             TheInfo: FInfo;
  1572.             ByteCount, FileSize: LongInt;
  1573.             AutoSelectAll: boolean;
  1574.             tLine: LineType;
  1575.     begin
  1576.         err := GetFInfo(fname, RefNum, TheInfo);
  1577.         case err of
  1578.             NoErr: 
  1579.                 if TheInfo.fdType <> 'TEXT' then begin
  1580.                         TypeMismatch(fname);
  1581.                         exit(ExportAsText)
  1582.                     end;
  1583.             FNFerr:  begin
  1584.                     err := create(fname, RefNum, TextCreator, 'TEXT');
  1585.                     if CheckIO(err) <> 0 then
  1586.                         exit(ExportAsText);
  1587.                 end;
  1588.             otherwise
  1589.                 if CheckIO(err) <> 0 then
  1590.                     exit(ExportAsText)
  1591.         end;
  1592.         ShowWatch;
  1593.         err := fsopen(fname, RefNum, f);
  1594.         if CheckIO(err) <> 0 then
  1595.             exit(ExportAsText);
  1596.         AutoSelectAll := not info^.RoiShowing;
  1597.         if AutoSelectAll then
  1598.             SelectAll(true);
  1599.         if TooWide then
  1600.             exit(ExportAsText);
  1601.         FileSize := 0;
  1602.         with info^.RoiRect do begin
  1603.                 width := right - left;
  1604.                 for vloc := top to bottom - 1 do begin
  1605.                         GetLine(left, vloc, width, tLine);
  1606.                         TextBufSize := 0;
  1607.                         for hloc := 0 to width - 1 do begin
  1608.                                 PutLong(tLine[hloc], 0);
  1609.                                 if hloc <> (width - 1) then
  1610.                                     PutTab;
  1611.                             end;
  1612.                         PutChar(cr);
  1613.                         ByteCount := TextBufSize;
  1614.                         err := fswrite(f, ByteCount, ptr(TextBufP));
  1615.                         FIleSize := FileSize + ByteCount;
  1616.                         if (CheckIO(err) <> 0) or CommandPeriod then
  1617.                             leave;
  1618.                     end;
  1619.                 err := SetEof(f, FileSize);
  1620.                 err := fsclose(f);
  1621.                 err := FlushVol(nil, RefNum);
  1622.             end;
  1623.         if AutoSelectAll then
  1624.             KillRoi;
  1625.     end;
  1626.  
  1627.  
  1628.     procedure ExportCoordinates (fname: str255; RefNum: integer);
  1629.         var
  1630.             err, f, i, y: integer;
  1631.             TheInfo: FInfo;
  1632.             ByteCount, FileSize: LongInt;
  1633.             InvertY: boolean;
  1634.     begin
  1635.         if not CoordinatesAvailableMsg then begin
  1636.                 exit(ExportCoordinates)
  1637.             end;
  1638.         err := GetFInfo(fname, RefNum, TheInfo);
  1639.         case err of
  1640.             NoErr: 
  1641.                 if TheInfo.fdType <> 'TEXT' then begin
  1642.                         TypeMismatch(fname);
  1643.                         exit(ExportCoordinates)
  1644.                     end;
  1645.             FNFerr:  begin
  1646.                     err := create(fname, RefNum, TextCreator, 'TEXT');
  1647.                     if CheckIO(err) <> 0 then
  1648.                         exit(ExportCoordinates);
  1649.                 end;
  1650.             otherwise
  1651.                 if CheckIO(err) <> 0 then
  1652.                     exit(ExportCoordinates)
  1653.         end;
  1654.         ShowWatch;
  1655.         err := fsopen(fname, RefNum, f);
  1656.         if CheckIO(err) <> 0 then
  1657.             exit(ExportCoordinates);
  1658.         FileSize := 0;
  1659.         InvertY := InvertYCoordinates and (Info <> NoInfo);
  1660.         with info^ do
  1661.             for i := 1 to nCoordinates do begin
  1662.                     TextBufSize := 0;
  1663.                     PutLong(xCoordinates^[i] + RoiRect.left, 0);
  1664.                     PutTab;
  1665.                     y := yCoordinates^[i] + RoiRect.top;
  1666.                     if InvertY then
  1667.                         y := PicRect.bottom - y - 1;
  1668.                     PutLong(y, 0);
  1669.                     PutChar(cr);
  1670.                     ByteCount := TextBufSize;
  1671.                     err := fswrite(f, ByteCount, ptr(TextBufP));
  1672.                     FIleSize := FileSize + ByteCount;
  1673.                     if (CheckIO(err) <> 0) or CommandPeriod then
  1674.                         leave;
  1675.                 end;
  1676.         err := SetEof(f, FileSize);
  1677.         err := fsclose(f);
  1678.         err := FlushVol(nil, RefNum);
  1679.     end;
  1680.  
  1681.  
  1682.     procedure ExportMeasurements (fname: str255; RefNum: integer);
  1683.         const
  1684.             LinesPerPass = 25;
  1685.         var
  1686.             err, f, i, first, last: integer;
  1687.             TheInfo: FInfo;
  1688.             ByteCount, FileSize: LongInt;
  1689.     begin
  1690.         err := GetFInfo(fname, RefNum, TheInfo);
  1691.         case err of
  1692.             NoErr: 
  1693.                 if TheInfo.fdType <> 'TEXT' then begin
  1694.                         TypeMismatch(fname);
  1695.                         exit(ExportMeasurements)
  1696.                     end;
  1697.             FNFerr:  begin
  1698.                     err := create(fname, RefNum, TextCreator, 'TEXT');
  1699.                     if CheckIO(err) <> 0 then
  1700.                         exit(ExportMeasurements);
  1701.                 end;
  1702.             otherwise
  1703.                 if CheckIO(err) <> 0 then
  1704.                     exit(ExportMeasurements)
  1705.         end;
  1706.         ShowWatch;
  1707.         err := fsopen(fname, RefNum, f);
  1708.         if CheckIO(err) <> 0 then
  1709.             exit(ExportMeasurements);
  1710.         FileSize := 0;
  1711.         first := 1;
  1712.         last := LinesPerPass;
  1713.         repeat
  1714.             if last > mCount then
  1715.                 last := mCount;
  1716.             CopyResultsToBuffer(first, last, ShowHeadings or OptionKeyWasDown);
  1717.             ByteCount := TextBufSize;
  1718.             err := fswrite(f, ByteCount, ptr(TextBufP));
  1719.             FIleSize := FileSize + ByteCount;
  1720.             if (CheckIO(err) <> 0) or CommandPeriod or (last = mCount) then
  1721.                 leave;
  1722.             first := first + LinesPerPass;
  1723.             last := last + LinesPerPass;
  1724.         until false;
  1725.         err := SetEof(f, FileSize);
  1726.         err := fsclose(f);
  1727.         err := FlushVol(nil, RefNum);
  1728.         UnsavedResults := false;
  1729.     end;
  1730.  
  1731.  
  1732.     procedure Swap2Bytes (var i: integer);
  1733.         type
  1734.             atype = packed array[1..2] of char;
  1735.         var
  1736.             a: atype;
  1737.             c: char;
  1738.     begin
  1739.         a := atype(i);
  1740.         c := a[1];
  1741.         a[1] := a[2];
  1742.         a[2] := c;
  1743.         i := integer(a)
  1744.     end;
  1745.  
  1746.  
  1747.     procedure Swap4Bytes (var i: LongInt);
  1748.         var
  1749.             a: ostype;
  1750.             c: char;
  1751.     begin
  1752.         a := ostype(i);
  1753.         c := a[1];
  1754.         a[1] := a[4];
  1755.         a[4] := c;
  1756.         c := a[2];
  1757.         a[2] := a[3];
  1758.         a[3] := c;
  1759.         i := LongInt(a)
  1760.     end;
  1761.  
  1762.  
  1763.     function OpenTiffHeader (f: integer; var DirOffset: LongInt): boolean;
  1764.         var
  1765.             TiffHeader: TiffHdr;
  1766.             ByteCount: LongInt;
  1767.             err: OSErr;
  1768.     begin
  1769.         ByteCount := 8;
  1770.         err := SetFPos(f, fsFromStart, 0);
  1771.         err := fsread(f, ByteCount, @TiffHeader);
  1772.         if CheckIO(err) <> NoErr then begin
  1773.                 OpenTiffHeader := false;
  1774.                 exit(OpenTiffHeader);
  1775.             end;
  1776.         with TiffHeader do begin
  1777.                 IntelByteOrder := ByteOrder = 'II';
  1778.                 if (ByteOrder <> 'MM') and (ByteOrder <> 'II') then begin
  1779.                         PutMessage('Invalid TIFF header.');
  1780.                         OpenTiffHeader := false;
  1781.                         exit(OpenTiffHeader)
  1782.                     end;
  1783.                 DirOffset := FirstIFDOffset;
  1784.                 if IntelByteOrder then
  1785.                     Swap4Bytes(DirOffset);
  1786.                 OpenTiffHeader := true;
  1787.             end;
  1788.     end;
  1789.  
  1790.  
  1791.     procedure GetTiffEntry (f: integer; var tag: integer; var N, value: LongInt);
  1792.         var
  1793.             IFDEntry: TiffEntry;
  1794.             ByteCount: LongInt;
  1795.             IntValue: integer;
  1796.             err: OSErr;
  1797.             str: str255;
  1798.     begin
  1799.         ByteCount := 12;
  1800.         err := FSRead(f, ByteCount, @IFDEntry);
  1801.         with IFDEntry do begin
  1802.                 tag := TagField;
  1803.                 N := length;
  1804.                 if IntelByteOrder then begin
  1805.                         Swap2Bytes(tag);
  1806.                         Swap2Bytes(ftype);
  1807.                         Swap4Bytes(N);
  1808.                     end;
  1809.                 value := offset;
  1810.                 if (ftype = short) and (N = 1) then begin
  1811.                         value := bsr(value, 16);
  1812.                         if IntelByteOrder then begin
  1813.                                 IntValue := value;
  1814.                                 Swap2Bytes(IntValue);
  1815.                                 value := IntValue
  1816.                             end
  1817.                     end
  1818.                 else if IntelByteOrder then
  1819.                     Swap4Bytes(value);
  1820.                 if OptionKeyWasDown then begin
  1821.                         gstr := concat(gstr, long2str(tag), '  ', long2str(ftype), '  ', long2str(N), '  ', long2str(value), cr);
  1822.                         ShowMessage(gstr);
  1823.                     end;
  1824.             end;
  1825.     end;
  1826.  
  1827.  
  1828.     function OpenTiffDirectory (f: integer; DirOffset: LongInt; var TiffInfo: TiffInfoRec; Importing: boolean): boolean;
  1829.         const
  1830.             NoUnit = 1;
  1831.             inch = 2;
  1832.             centimeter = 3;
  1833.         var
  1834.             ByteCount, length, ftype, N, value, BytesPerStrip, SaveFPos: LongInt;
  1835.             err: OSErr;
  1836.             nEntries, i, tag, entry: integer;
  1837.             StripOffsetsArray: array[1..2] of LongInt;
  1838.             xRes, yRes: extended;
  1839.  
  1840.         function GetResolution: extended;
  1841.             var
  1842.                 resolution: array[1..2] of LongInt;
  1843.         begin
  1844.             err := GetFPos(f, SaveFPos);
  1845.             err := SetFPos(f, fsFromStart, value);
  1846.             ByteCount := 8;
  1847.             err := fsread(f, ByteCount, @Resolution);
  1848.             if IntelByteOrder then begin
  1849.                     Swap4Bytes(Resolution[1]);
  1850.                     Swap4Bytes(Resolution[2]);
  1851.                 end;
  1852.             err := SetFPos(f, fsFromStart, SaveFPos);
  1853.             if resolution[2] <> 0 then
  1854.                 GetResolution := resolution[1] / resolution[2]
  1855.             else
  1856.                 GetResolution := 0.0;
  1857.         end;
  1858.  
  1859.     begin
  1860.         if OptionKeyWasDown then
  1861.             gstr := '';
  1862.         xRes := 0.0;
  1863.         err := SetFPos(f, fsFromStart, DirOffset);
  1864.         ByteCount := 2;
  1865.         err := FSRead(f, ByteCount, @nEntries);
  1866.         if CheckIO(err) <> NoErr then begin
  1867.                 OpenTiffDirectory := false;
  1868.                 exit(OpenTiffDirectory);
  1869.             end;
  1870.         if IntelByteOrder then
  1871.             Swap2Bytes(nEntries);
  1872.         with TiffInfo do begin
  1873.                 width := 0;
  1874.                 height := 0;
  1875.                 BitsPerPixel := 1;
  1876.                 OffsetToData := 0;
  1877.                 Resolution := 0.0;
  1878.                 ResUnits := tNoUnits;
  1879.                 OffsetToColorMap := 0;
  1880.                 OffsetToImageHeader := -1;
  1881.                 for entry := 1 to nEntries do begin
  1882.                         GetTiffEntry(f, tag, N, value);
  1883.                         if tag = 0 then begin
  1884.                                 PutMessage('Invalid TIFF format.');
  1885.                                 OpenTiffDirectory := false;
  1886.                                 exit(OpenTiffDirectory)
  1887.                             end;
  1888.                         case tag of
  1889.                             ImageWidth: 
  1890.                                 width := value;
  1891.                             ImageLength: 
  1892.                                 height := value;
  1893.                             BitsPerSample:  begin
  1894.                                     BitsPerPixel := value;
  1895.                                     if value = 1 then begin
  1896.                                             PutMessage('NIH Image cannot open 1-bit TIFF files.');
  1897.                                             OpenTiffDirectory := false;
  1898.                                             exit(OpenTiffDirectory)
  1899.                                         end;
  1900.                                     if (value = 16) and not importing then begin
  1901.                                             PutMessage('Use Import to open 16-bit TIFF files.');
  1902.                                             OpenTiffDirectory := false;
  1903.                                             exit(OpenTiffDirectory)
  1904.                                         end;
  1905.                                 end;
  1906.                             SamplesPerPixel: 
  1907.                                 if value > 1 then begin
  1908.                                         PutMessage('NIH Image cannot open 24-bit TIFF files.');
  1909.                                         OpenTiffDirectory := false;
  1910.                                         exit(OpenTiffDirectory)
  1911.                                     end;
  1912.                             Compression: 
  1913.                                 if value <> 1 then begin
  1914.                                         PutMessage('NIH Image cannot open compressed TIFF files.');
  1915.                                         OpenTiffDirectory := false;
  1916.                                         exit(OpenTiffDirectory)
  1917.                                     end;
  1918.                             PhotoInterp: 
  1919.                                 ZeroIsBlack := value = 1;
  1920.                             StripOffsets: 
  1921.                                 if N = 1 then
  1922.                                     OffsetToData := value
  1923.                                 else begin
  1924.                                         err := GetFPos(f, SaveFPos);
  1925.                                         err := SetFPos(f, fsFromStart, value);
  1926.                                         ByteCount := 8;
  1927.                                         err := fsread(f, ByteCount, @StripOffsetsArray);
  1928.                                         if IntelByteOrder then begin
  1929.                                                 Swap4Bytes(StripOffsetsArray[1]);
  1930.                                                 Swap4Bytes(StripOffsetsArray[2]);
  1931.                                             end;
  1932.                                         err := SetFPos(f, fsFromStart, SaveFPos);
  1933.                                     end;
  1934.                             RowsPerStrip: 
  1935.                                 if value < height then begin
  1936.                                         if BitsPerPixel = 16 then
  1937.                                             BytesPerStrip := value * width * 2
  1938.                                         else
  1939.                                             BytesPerStrip := value * width;
  1940.                                         if StripOffsetsArray[2] <> (StripOffsetsArray[1] + BytesPerStrip) then begin
  1941.                                                 PutMessage('NIH Image cannot open TIFF files with discontiguous strips.');
  1942.                                                 OpenTiffDirectory := false;
  1943.                                                 exit(OpenTiffDirectory)
  1944.                                             end;
  1945.                                         OffsetToData := StripOffsetsArray[1];
  1946.                                     end;
  1947.                             XResolution: 
  1948.                                 XRes := GetResolution;
  1949.                             YResolution:  begin
  1950.                                     yRes := GetResolution;
  1951.                                     if (xRes = yRes) and (xRes > 0.0) then begin
  1952.                                             resolution := xRes;
  1953.                                             ResUnits := tInches;
  1954.                                         end;
  1955.                                 end;
  1956.                             ResolutionUnit: 
  1957.                                 case value of
  1958.                                     NoUnit: 
  1959.                                         ResUnits := tNoUnits;
  1960.                                     Centimeter: 
  1961.                                         ResUnits := tCentimeters;
  1962.                                     otherwise
  1963.                                 end;
  1964.                             ColorMapTag: 
  1965.                                 if N = 768 then
  1966.                                     OffsetToColorMap := value;
  1967.                             ImageHdrTag: 
  1968.                                 OffsetToImageHeader := value;
  1969.                             otherwise
  1970.                         end;
  1971.                     end; {for}
  1972.                 ByteCount := 4;
  1973.                 err := FSRead(f, ByteCount, @NextIFD);
  1974.                 if IntelByteOrder then
  1975.                     Swap4Bytes(NextIFD);
  1976.                 if OptionKeyWasDown then begin
  1977.                         gstr := concat(gstr, 'Next IFD=', long2str(NextIFD));
  1978.                         ShowMessage(gstr);
  1979.                     end;
  1980.                 if width = 0 then begin
  1981.                         PutMessage('Error opening TIFF directory');
  1982.                         OpenTiffDirectory := false;
  1983.                         exit(OpenTiffDirectory)
  1984.                     end;
  1985.             end; {with}
  1986.         OpenTiffDirectory := true;
  1987.     end;
  1988.  
  1989.  
  1990.     procedure SaveTiffColorMap (f: integer; ImageDataSize: LongInt);
  1991.         var
  1992.             i: integer;
  1993.             err: OSErr;
  1994.             ColorMap: TiffColorMapType;
  1995.             ColorMapSize: LongInt;
  1996.     begin
  1997.         LoadLUT(info^.cTable);
  1998.         for i := 0 to 255 do
  1999.             with cScreenPort^.portPixMap^^.pmTable^^.ctTable[i].rgb do begin
  2000.                     ColorMap[1, i] := red;
  2001.                     ColorMap[2, i] := green;
  2002.                     ColorMap[3, i] := blue;
  2003.                 end;
  2004.         err := SetFPos(f, FSFromStart, HeaderSize + TiffDirSize + ImageDataSize);
  2005.         ColorMapSize := SizeOf(ColorMap);
  2006.         err := fswrite(f, ColorMapSize, @ColorMap);
  2007.         if CheckIO(err) <> 0 then
  2008.             beep;
  2009.     end;
  2010.  
  2011.  
  2012.     procedure GetTiffColorMap (f: integer);
  2013.         var
  2014.             i: integer;
  2015.             ByteCount: LongInt;
  2016.             err: OSErr;
  2017.             ColorMap: TiffColorMapType;
  2018.     begin
  2019.         with info^ do begin
  2020.                 ByteCount := SizeOf(ColorMap);
  2021.                 err := SetFPos(f, fsFromStart, ColorMapOffset);
  2022.                 err := fsRead(f, ByteCount, @ColorMap);
  2023.                 if err = NoErr then begin
  2024.                         if IntelByteOrder then
  2025.                             for i := 0 to 255 do begin
  2026.                                     Swap2Bytes(ColorMap[1, i]);
  2027.                                     Swap2Bytes(ColorMap[2, i]);
  2028.                                     Swap2Bytes(ColorMap[3, i]);
  2029.                                 end;
  2030.                         for i := 0 to 255 do
  2031.                             with cTable[i].rgb do begin
  2032.                                     red := ColorMap[1, i];
  2033.                                     green := ColorMap[2, i];
  2034.                                     blue := ColorMap[3, i];
  2035.                                 end;
  2036.                         LoadLUT(cTable);
  2037.                         LUTMode := ColorLut;
  2038.                         SetupPseudocolor;
  2039.                         IdentityFunction := false;
  2040.                         if isGrayScaleLUT then begin
  2041.                                 info^.LutMode := CustomGrayScale;
  2042.                                 DrawMap;
  2043.                             end;
  2044.                     end
  2045.                 else
  2046.                     beep;
  2047.             end;{with}
  2048.     end;
  2049.  
  2050.  
  2051.     function SaveTiffDir (f, slines, sPixelsPerLine: integer; SavingSelection: boolean; ctabSize, ImageDataSize: LongInt): OSErr;
  2052.         var
  2053.             i: integer;
  2054.             err: OSErr;
  2055.             ByteCount, width, height: LongInt;
  2056.             TiffInfo1: record
  2057.                     Header: TiffHdr;   {8}
  2058.                     nEntries: integer; {2}
  2059.                     TiffDir: array[1..8] of TiffEntry; {96}
  2060.                 end;
  2061.             ColorMapEntry: TiffEntry;  {12(Optional)}
  2062.             TiffInfo2: record
  2063.                     ImageHdrEntry: TiffEntry;  {12}
  2064.                     NextIFD: LongInt;  {4}
  2065.                     filler: array[1..TiffFillerSize] of integer; {134}
  2066.                 end;
  2067.     begin
  2068.         with info^ do begin
  2069.                 if SavingSelection then begin
  2070.                         width := sPixelsPerLine;
  2071.                         height := sLines
  2072.                     end
  2073.                 else begin
  2074.                         width := PixelsPerLine;
  2075.                         height := nLines
  2076.                     end;
  2077.                 with TiffInfo1 do begin
  2078.                         with header do begin
  2079.                                 ByteOrder := 'MM';
  2080.                                 Version := 42;
  2081.                                 FirstIFDOffset := 8;
  2082.                             end;
  2083.                         if ctabSize > 0 then
  2084.                             nEntries := 10
  2085.                         else
  2086.                             nEntries := 9;
  2087.                         for i := 1 to 8 do
  2088.                             with TiffDir[i] do begin
  2089.                                     ftype := 3;
  2090.                                     length := 1
  2091.                                 end;
  2092.                         with TiffDir[1] do begin
  2093.                                 TagField := NewSubfileType;
  2094.                                 ftype := 4;
  2095.                                 offset := 0;
  2096.                             end;
  2097.                         with TiffDir[2] do begin
  2098.                                 TagField := ImageWidth;
  2099.                                 offset := bsl(width, 16);
  2100.                             end;
  2101.                         with TiffDir[3] do begin
  2102.                                 TagField := ImageLength;
  2103.                                 offset := bsl(height, 16);
  2104.                             end;
  2105.                         with TiffDir[4] do begin
  2106.                                 TagField := BitsPerSample;
  2107.                                 offset := bsl(8, 16);
  2108.                             end;
  2109.                         with TiffDir[5] do begin
  2110.                                 TagField := PhotoInterp;
  2111.                                 if ctabSize > 0 then
  2112.                                     offset := bsl(3, 16)
  2113.                                 else
  2114.                                     offset := 0;
  2115.                             end;
  2116.                         with TiffDir[6] do begin
  2117.                                 TagField := StripOffsets;
  2118.                                 ftype := 4;
  2119.                                 offset := TiffDirSize + HeaderSize;
  2120.                             end;
  2121.                         with TiffDir[7] do begin
  2122.                                 TagField := RowsPerStrip;
  2123.                                 offset := bsl(height, 16);
  2124.                             end;
  2125.                         with TiffDir[8] do begin
  2126.                                 TagField := StripByteCount;
  2127.                                 ftype := 4;
  2128.                                 offsetname, RefNum);
  2129.                 exit(SaveLUT)
  2130.             end;
  2131.         err := SetEof(f, ByteCount);
  2132.         err := fsclose(f);
  2133.         err := GetFInfo(fname, RefNum, TheInfo);
  2134.         if TheInfo.fdCreator <> 'Imag' then begin
  2135.                 TheInfo.fdCreator := 'Imag';
  2136.                 err := SetFInfo(fname, RefNum, TheInfo);
  2137.             end;
  2138.         err := FlushVol(nil, RefNum);
  2139.     end;
  2140.  
  2141.  
  2142.     procedure SaveColorTable (fname: str255; RefNum: integer);
  2143.         var
  2144.             err: integer;
  2145.             TheInfo: FInfo;
  2146.             i, f: integer;
  2147.             ByteCount: LongInt;
  2148.             hdr: PaletteHeader;
  2149.     begin
  2150.         with info^ do
  2151.             err := GetFInfo(fname, RefNum, TheInfo);
  2152.         case err of
  2153.             NoErr: 
  2154.                 if TheInfo.fdType <> 'ICOL' then begin
  2155.                         TypeMismatch(fname);
  2156.                         exit(SaveColorTable)
  2157.                     end;
  2158.             FNFerr:  begin
  2159.                     err := create(fname, RefNum, 'Imag', 'ICOL');
  2160.                     if CheckIO(err) <> 0 then
  2161.                         exit(SaveColorTable);
  2162.                 end;
  2163.             otherwise
  2164.                 if CheckIO(err) <> 0 then
  2165.                     exit(SaveColorTable);
  2166.         end;
  2167.         with info^ do begin
  2168.                 InitPaletteHeader(hdr);
  2169.                 err := fsopen(fname, RefNum, f);
  2170.                 if CheckIO(err) <> 0 then
  2171.                     exit(SaveColorTable);
  2172.                 err := SetFPos(f, FSFromStart, 0);
  2173.                 ByteCount := SizeOf(PaletteHeader);
  2174.                 if ByteCount <> 32 then
  2175.                     PutMessage('Palette header size <> 32.');
  2176.                 err := fswrite(f, ByteCount, @hdr);
  2177.                 ByteCount := nColors;
  2178.                 err := fswrite(f, ByteCount, @redLUT);
  2179.                 ByteCount := nColors;
  2180.                 err := fswrite(f, ByteCount, @greenLUT);
  2181.                 ByteCount := nColors;
  2182.                 err := fswrite(f, ByteCount, @blueLUT);
  2183.                 if CheckIO(err) <> 0 then begin
  2184.                         err := fsclose(f);
  2185.                         err := FSDelete(fname, RefNum);
  2186.                         exit(SaveColorTable)
  2187.                     end;
  2188.                 err := SetEOF(f, SizeOf(PaletteHeader) + 3 * nColors);
  2189.                 err := fsclose(f);
  2190.                 err := GetFInfo(fname, RefNum, TheInfo);
  2191.                 if TheInfo.fdCreator <> 'Imag' then begin
  2192.                         TheInfo.fdCreator := 'Imag';
  2193.                         err := SetFInfo(fname, RefNum, TheInfo);
  2194.                     end;
  2195.                 err := FlushVol(nil, RefNum);
  2196.             end; {with info^}
  2197.     end;
  2198.  
  2199.  
  2200.     procedure SaveOutline (fname: str255; RefNum: integer);
  2201.         var
  2202.             err: integer;
  2203.             TheInfo: FInfo;
  2204.             i, f: integer;
  2205.             ByteCount, DataSize: LongInt;
  2206.             hdr: RoiHeader;
  2207.             SaveCoordinates: boolean;
  2208.     begin
  2209.         with info^ do begin
  2210.                 if not RoiShowing then begin
  2211.                         PutMessage('No outline available to save.');
  2212.                         exit(SaveOutline);
  2213.                     end;
  2214.                 if (RoiType = FreeLineRoi) or (RoiType = SegLineRoi) then begin
  2215.                         PutMessage('Freehand and segmented line selections cannot be saved.');
  2216.                         exit(SaveOutline);
  2217.                     end;
  2218.                 SaveCoordinates := (RoiType = PolygonRoi) or (RoiType = FreehandRoi);
  2219.                 if SaveCoordinates then
  2220.                     if not CoordinatesAvailableMsg then begin
  2221.                             exit(SaveOutline);
  2222.                         end;
  2223.                 err := GetFInfo(fname, RefNum, TheInfo);
  2224.                 case err of
  2225.                     NoErr: 
  2226.                         if TheInfo.fdType <> 'Iout' then begin
  2227.                                 TypeMismatch(fname);
  2228.                                 exit(SaveOutline)
  2229.                             end;
  2230.                     FNFerr:  begin
  2231.                             err := create(fname, RefNum, 'Imag', 'Iout');
  2232.                             if CheckIO(err) <> 0 then
  2233.                                 exit(SaveOutline);
  2234.                         end;
  2235.                     otherwise
  2236.                         if CheckIO(err) <> 0 then
  2237.                             exit(SaveOutline);
  2238.                 end;
  2239.                 with hdr do begin
  2240.                         rID := 'Iout';
  2241.                         rVersion := version;
  2242.                         rRoiType := RoiType;
  2243.                         rRoiRect := RoiRect;
  2244.                         rNCoordinates := nCoordinates;
  2245.                         GetLoi(rX1, rY1, rX2, rY2);
  2246.                         rLineWidth := LineWidth;
  2247.                         for i := 1 to 14 do
  2248.                             rUnused[i] := 0;
  2249.                     end;
  2250.                 err := fsopen(fname, RefNum, f);
  2251.                 if CheckIO(err) <> 0 then
  2252.                     exit(SaveOutline);
  2253.                 err := SetFPos(f, FSFromStart, 0);
  2254.                 ByteCount := SizeOf(RoiHeader);
  2255.                 if ByteCount <> 64 then
  2256.                     PutMessage('Roi header size <> 32.');
  2257.                 err := fswrite(f, ByteCount, @hdr);
  2258.                 if SaveCoordinates then begin
  2259.                         ByteCount := nCoordinates * 2;
  2260.                         err := fswrite(f, ByteCount, ptr(xCoordinates));
  2261.                         ByteCount := nCoordinates * 2;
  2262.                         err := fswrite(f, ByteCount, ptr(yCoordinates));
  2263.                         DataSize := nCoordinates * 4;
  2264.                     end
  2265.                 else
  2266.                     DataSize := 0;
  2267.                 if CheckIO(err) <> 0 then begin
  2268.                         err := fsclose(f);
  2269.                         err := FSDelete(fname, RefNum);
  2270.                         exit(SaveOutline)
  2271.                     end;
  2272.                 err := SetEOF(f, SizeOf(RoiHeader) + DataSize);
  2273.                 err := fsclose(f);
  2274.                 err := GKind := Micrometers;
  2275.                         UnitsPerCm := 10000.0;
  2276.                     end
  2277.                 else if xUnit = 'mm' then begin
  2278.                         UnitsKind := Millimeters;
  2279.                         UnitsPerCm := 10.0;
  2280.                     end
  2281.                 else if xUnit = 'cm' then begin
  2282.                         UnitsKind := Centimeters;
  2283.                         UnitsPerCm := 1.0;
  2284.                     end
  2285.                 else if xUnit = 'meter' then begin
  2286.                         UnitsKind := Meters;
  2287.                         UnitsPerCm := 0.01;
  2288.                     end
  2289.                 else if xUnit = 'km' then begin
  2290.                         UnitsKind := Kilometers;
  2291.                         UnitsPerCm := 0.00001;
  2292.                     end
  2293.                 else if xUnit = 'inch' then begin
  2294.                         UnitsKind := Inches;
  2295.                         UnitsPerCm := 0.3937;
  2296.                     end
  2297.                 else if xUnit = 'ft' then begin
  2298.                         UnitsKind := feet;
  2299.                         UnitsPerCm := 0.0328083;
  2300.                     end
  2301.                 else if xUnit = 'mile' then begin
  2302.                         UnitsKind := Miles;
  2303.                         UnitsPerCm := 0.000006213;
  2304.                     end
  2305.                 else if xUnit = 'pixel' then begin
  2306.                         UnitsKind := pixels;
  2307.                         UnitsPerCm := 0.0;
  2308.                         SpatiallyCalibrated := false;
  2309.                     end
  2310.                 else begin
  2311.                         UnitsKind := OtherUnits;
  2312.                         UnitsPerCm := 0.0;
  2313.                     end;
  2314.             end;
  2315.     end;
  2316.  
  2317.  
  2318. end.